home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 45
/
Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso
/
Aminet
/
gfx
/
x11
/
x3270_3_2_16.lha
/
amiga_src
/
CmplxMenu.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-06-23
|
41KB
|
1,405 lines
/* (from) $XConsortium: SimpleMenu.c,v 1.41 92/09/10 16:25:07 converse Exp $ */
/*
* Modifications Copyright 1995, 1999 by Paul Mattes.
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* Copyright 1989 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. M.I.T. makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* ComplexMenu.c - Source code file for ComplexMenu widget.
* (from) SimpleMenu.c - Source code file for SimpleMenu widget.
*
* Date: April 3, 1989
*
* By: Chris D. Peterson
* MIT X Consortium
* kit@expo.lcs.mit.edu
*/
#include "globals.h"
#if defined(X3270_MENUS) /*[*/
#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/XawInit.h>
#include "CmplxMenuP.h"
#include "CmeBSB.h"
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xmu/Initer.h>
#include <X11/Xmu/CharSet.h>
#include <x11/X.h>
#include <x11/Intrinsic.h>
#include <x11/Shell.h>
#include <x11/ShellP.h>
#define streq(a, b) ( strcmp((a), (b)) == 0 )
#define offset(field) XtOffsetOf(ComplexMenuRec, complex_menu.field)
static XtResource resources[] = {
/*
* Label Resources.
*/
{XtNlabel, XtCLabel, XtRString, sizeof(String),
offset(label_string), XtRString, NULL},
{XtNlabelClass, XtCLabelClass, XtRPointer, sizeof(WidgetClass),
offset(label_class), XtRImmediate, (XtPointer) NULL},
/*
* Layout Resources.
*/
{XtNrowHeight, XtCRowHeight, XtRDimension, sizeof(Dimension),
offset(row_height), XtRImmediate, (XtPointer) 0},
{XtNtopMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
offset(top_margin), XtRImmediate, (XtPointer) 0},
{XtNbottomMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
offset(bottom_margin), XtRImmediate, (XtPointer) 0},
/*
* Misc. Resources
*/
{ XtNallowShellResize, XtCAllowShellResize, XtRBoolean, sizeof(Boolean),
XtOffsetOf(ComplexMenuRec, shell.allow_shell_resize),
XtRImmediate, (XtPointer) TRUE },
{XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
offset(cursor), XtRImmediate, (XtPointer) None},
{XtNmenuOnScreen, XtCMenuOnScreen, XtRBoolean, sizeof(Boolean),
offset(menu_on_screen), XtRImmediate, (XtPointer) TRUE},
{XtNpopupOnEntry, XtCPopupOnEntry, XtRWidget, sizeof(Widget),
offset(popup_entry), XtRWidget, NULL},
{XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
offset(backing_store),
XtRImmediate, (XtPointer) (Always + WhenMapped + NotUseful)},
{XtNcMparent, XtCCMparent, XtRWidget, sizeof(Widget),
offset(parent), XtRWidget, NULL},
{XtNcMdefer, XtCCMdefer, XtRWidget, sizeof(Widget),
offset(deferred_notify), XtRWidget, NULL},
};
#undef offset
static char defaultTranslations[] =
"<EnterWindow>: highlight() \n\
<LeaveWindow>: leftWindow() \n\
<BtnMotion>: highlight() \n\
<BtnUp>: saveUnhighlight() MenuPopdown()";
/*
* Semi Public function definitions.
*/
static void Redisplay(Widget, XEvent *, Region);
static void Realize(Widget, XtValueMask *, XSetWindowAttributes *);
static void ChangeManaged(Widget);
static void Resize(Widget);
static void Initialize(Widget, Widget, ArgList, Cardinal *);
static void ClassInitialize(void);
static void ClassPartInitialize(WidgetClass);
static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
static Boolean SetValuesHook(Widget, ArgList, Cardinal *);
static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
XtWidgetGeometry *);
/*
* Action Routine Definitions
*/
static void PositionMenuAction(Widget, XEvent *, String *, Cardinal *);
static void SaveUnhighlight(Widget, XEvent *, String *, Cardinal *);
static void LeftWindow(Widget, XEvent *, String *, Cardinal *);
static void Highlight(Widget, XEvent *, String *, Cardinal *);
/*
* Private Function Definitions.
*/
static void Unhighlight(), Notify();
static void MakeSetValuesRequest(Widget, Dimension, Dimension);
static void Layout(Widget, Dimension *, Dimension *);
static void CreateLabel(Widget);
static void AddPositionAction(XtAppContext, caddr_t);
static void ChangeCursorOnGrab(Widget, XtPointer junk, XtPointer);
static void PositionMenu(Widget, XPoint *);
static void ClearParent(Widget, XtPointer, XtPointer);
static Dimension GetMenuWidth(Widget, Widget);
static Dimension GetMenuHeight(Widget);
static Widget FindMenu(Widget, String);
static CmeObject GetEventEntry(Widget, XEvent *);
static CmeObject GetRightEntry(Widget, XEvent *);
static void MoveMenu(Widget, Position, Position);
static XtActionsRec actionsList[] =
{
{"highlight", Highlight},
{"saveUnhighlight", SaveUnhighlight},
{"leftWindow", LeftWindow},
};
static CompositeClassExtensionRec extension_rec = {
/* next_extension */ NULL,
/* record_type */ NULLQUARK,
/* version */ XtCompositeExtensionVersion,
/* record_size */ sizeof(CompositeClassExtensionRec),
/* accepts_objects */ TRUE,
};
#ifndef AMIGA
#define def_superclass (&overrideShellClassRec)
#else
#define def_superclass (overrideShellWidgetClass)
#endif
ComplexMenuClassRec complexMenuClassRec = {
{
/* superclass */ (WidgetClass)0,
/* class_name */ "ComplexMenu",
/* size */ sizeof(ComplexMenuRec),
/* class_initialize */ ClassInitialize,
/* class_part_initialize*/ ClassPartInitialize,
/* Class init'ed */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ Realize,
/* actions */ actionsList,
/* num_actions */ XtNumber(actionsList),
/* resources */ resources,
/* resource_count */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave*/ TRUE,
/* visible_interest */ FALSE,
/* destroy */ NULL,
/* resize */ Resize,
/* expose */ Redisplay,
/* set_values */ SetValues,
/* set_values_hook */ SetValuesHook,
/* set_values_almost */ 0,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* intrinsics version */ XtVersion,
/* callback offsets */ NULL,
/* tm_table */ defaultTranslations,
/* query_geometry */ NULL,
/* display_accelerator*/ NULL,
/* extension */ NULL
},{
/* geometry_manager */ GeometryManager,
/* change_managed */ ChangeManaged,
/* insert_child */ 0,
/* delete_child */ 0,
/* extension */ NULL
},{
/* Shell extension */ NULL
},{
/* Override extension */ NULL
},{
/* Complex Menu extension*/ NULL
}
};
WidgetClass complexMenuWidgetClass = (WidgetClass)&complexMenuClassRec;
#ifdef AMIGA
void AMIGA_INIT_CMPLXMENU(void)
{
complexMenuClassRec.superclass=def_superclass;
complexMenuClassRec.set_values_almost=XtInheritSetValuesAlmost;
complexMenuClassRec.insert_child=XtInheritInsertChild;
complexMenuClassRec.delete_child=XtInheritDeleteChild;
}
#endif
/************************************************************
*
* Semi-Public Functions.
*
************************************************************/
/* Function Name: ClassInitialize
* Description: Class Initialize routine, called only once.
* Arguments: none.
* Returns: none.
*/
void relay_func(
XrmValue* a/* args */,
Cardinal* b/* num_args */,
XrmValuePtr c/* fromVal */,
XrmValuePtr d/* toVal */
)
{
XmuCvtStringToBackingStore(a,b,c,d);
}
static void
ClassInitialize(void)
{
XawInitializeWidgetSet();
XtAddConverter( XtRString, XtRBackingStore, relay_func,
NULL, 0 );
XmuAddInitializer( AddPositionAction, NULL);
}
/* Function Name: ClassInitialize
* Description: Class Part Initialize routine, called for every
* subclass. Makes sure that the subclasses pick up
* the extension record.
* Arguments: wc - the widget class of the subclass.
* Returns: none.
*/
static void
ClassPartInitialize(WidgetClass wc)
{
ComplexMenuWidgetClass cmwc = (ComplexMenuWidgetClass) wc;
/*
* Make sure that our subclass gets the extension rec too.
*/
extension_rec.next_extension = cmwc->composite_class.extension;
cmwc->composite_class.extension = (XtPointer) &extension_rec;
}
/* Function Name: Initialize
* Description: Initializes the complex menu widget
* Arguments: request - the widget requested by the argument list.
* new - the new widget with both resource and non
* resource values.
* Returns: none.
*/
static void
Initialize(Widget request unused, Widget new, ArgList args unused,
Cardinal *num_args unused)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) new;
XmuCallInitializers(XtWidgetToApplicationContext(new));
if (cmw->complex_menu.label_class == NULL)
cmw->complex_menu.label_class = cmeBSBObjectClass;
cmw->complex_menu.label = NULL;
cmw->complex_menu.entry_set = NULL;
cmw->complex_menu.prev_entry = NULL;
cmw->complex_menu.recursive_set_values = FALSE;
if (cmw->complex_menu.label_string != NULL)
CreateLabel(new);
cmw->complex_menu.menu_width = TRUE;
if (cmw->core.width == 0) {
cmw->complex_menu.menu_width = FALSE;
cmw->core.width = GetMenuWidth(new, (Widget)NULL);
}
cmw->complex_menu.menu_height = TRUE;
if (cmw->core.height == 0) {
cmw->complex_menu.menu_height = FALSE;
cmw->core.height = GetMenuHeight(new);
}
/*
* Add a popup_callback routine for changing the cursor.
*/
XtAddCallback(new, XtNpopupCallback, ChangeCursorOnGrab, NULL);
/*
* Add a popdown_callback routine for clearing the parent field.
*/
XtAddCallback(new, XtNpopdownCallback, ClearParent, NULL);
}
/* Function Name: Redisplay
* Description: Redisplays the contents of the widget.
* Arguments: w - the complex menu widget.
* event - the X event that caused this redisplay.
* region - the region the needs to be repainted.
* Returns: none.
*/
static void
Redisplay(Widget w, XEvent *event unused, Region region)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
CmeObject * entry;
CmeObjectClass class;
if (region == NULL)
XClearWindow(XtDisplay(w), XtWindow(w));
/*
* Check and Paint each of the entries - including the label.
*/
ForAllChildren(cmw, entry) {
if (!XtIsManaged ( (Widget) *entry)) continue;
if (region != NULL)
switch(XRectInRegion(region, (int) (*entry)->rectangle.x,
(int) (*entry)->rectangle.y,
(unsigned int) (*entry)->rectangle.width,
(unsigned int) (*entry)->rectangle.height)) {
case RectangleIn:
case RectanglePart:
break;
default:
continue;
}
class = (CmeObjectClass) (*entry)->object.widget_class;
if (class->rect_class.expose != NULL)
(class->rect_class.expose)( (Widget) *entry, NULL, NULL);
}
}
/* Function Name: Realize
* Description: Realizes the widget.
* Arguments: w - the complex menu widget.
* mask - value mask for the window to create.
* attrs - attributes for the window to create.
* Returns: none
*/
static void
Realize(Widget w, XtValueMask *mask, XSetWindowAttributes *attrs)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
attrs->cursor = cmw->complex_menu.cursor;
*mask |= CWCursor;
if ((cmw->complex_menu.backing_store == Always) ||
(cmw->complex_menu.backing_store == NotUseful) ||
(cmw->complex_menu.backing_store == WhenMapped) ) {
*mask |= CWBackingStore;
attrs->backing_store = cmw->complex_menu.backing_store;
}
else
*mask &= ~CWBackingStore;
(*def_superclass->core_class.realize) (w, mask, attrs);
}
/* Function Name: Resize
* Description: Handle the menu being resized bigger.
* Arguments: w - the complex menu widget.
* Returns: none.
*/
static void
Resize(Widget w)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
CmeObject * entry;
if ( !XtIsRealized(w) ) return;
ForAllChildren(cmw, entry) /* reset width of all entries. */
if (XtIsManaged( (Widget) *entry))
(*entry)->rectangle.width = cmw->core.width;
Redisplay(w, (XEvent *) NULL, (Region) NULL);
}
/* Function Name: SetValues
* Description: Relayout the menu when one of the resources is changed.
* Arguments: current - current state of the widget.
* request - what was requested.
* new - what the widget will become.
* Returns: none
*/
static Boolean
SetValues(Widget current, Widget request unused, Widget new,
ArgList args unused, Cardinal *num_args unused)
{
ComplexMenuWidget cmw_old = (ComplexMenuWidget) current;
ComplexMenuWidget cmw_new = (ComplexMenuWidget) new;
Boolean ret_val = FALSE, layout = FALSE;
if (!XtIsRealized(current)) return(FALSE);
if (!cmw_new->complex_menu.recursive_set_values) {
if (cmw_new->core.width != cmw_old->core.width) {
cmw_new->complex_menu.menu_width = (cmw_new->core.width != 0);
layout = TRUE;
}
if (cmw_new->core.height != cmw_old->core.height) {
cmw_new->complex_menu.menu_height = (cmw_new->core.height != 0);
layout = TRUE;
}
}
if (cmw_old->complex_menu.cursor != cmw_new->complex_menu.cursor)
XDefineCursor(XtDisplay(new),
XtWindow(new), cmw_new->complex_menu.cursor);
if (cmw_old->complex_menu.label_string !=cmw_new->complex_menu.label_string) {
if (cmw_new->complex_menu.label_string == NULL) /* Destroy. */
XtDestroyWidget((Widget) cmw_old->complex_menu.label);
else if (cmw_old->complex_menu.label_string == NULL) /* Create. */
CreateLabel(new);
else { /* Change. */
Arg arglist[1];
XtSetArg(arglist[0], XtNlabel, cmw_new->complex_menu.label_string);
XtSetValues((Widget) cmw_new->complex_menu.label, arglist, ONE);
}
}
if (cmw_old->complex_menu.label_class != cmw_new->complex_menu.label_class)
XtAppWarning(XtWidgetToApplicationContext(new),
"No Dynamic class change of the ComplexMenu Label.");
if ((cmw_old->complex_menu.top_margin != cmw_new->complex_menu.top_margin) ||
(cmw_old->complex_menu.bottom_margin !=
cmw_new->complex_menu.bottom_margin) /* filler................. */ ) {
layout = TRUE;
ret_val = TRUE;
}
if (layout)
Layout(new, (Dimension *)NULL, (Dimension *)NULL);
return(ret_val);
}
/* Function Name: SetValuesHook
* Description: To handle a special case, this is passed the
* actual arguments.
* Arguments: w - the menu widget.
* arglist - the argument list passed to XtSetValues.
* num_args - the number of args.
* Returns: none
*/
/*
* If the user actually passed a width and height to the widget
* then this MUST be used, rather than our newly calculated width and
* height.
*/
static Boolean
SetValuesHook(Widget w, ArgList arglist, Cardinal *num_args)
{
register Cardinal i;
Dimension width, height;
width = w->core.width;
height = w->core.height;
for ( i = 0 ; i < *num_args ; i++) {
if ( streq(arglist[i].name, XtNwidth) )
width = (Dimension) arglist[i].value;
if ( streq(arglist[i].name, XtNheight) )
height = (Dimension) arglist[i].value;
}
if ((width != w->core.width) || (height != w->core.height))
MakeSetValuesRequest(w, width, height);
return(FALSE);
}
/************************************************************
*
* Geometry Management routines.
*
************************************************************/
/* Function Name: GeometryManager
* Description: This is the ComplexMenu Widget's Geometry Manager.
* Arguments: w - the Menu Entry making the request.
* request - requested new geometry.
* reply - the allowed geometry.
* Returns: XtGeometry{Yes, No, Almost}.
*/
static XtGeometryResult
GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) XtParent(w);
CmeObject entry = (CmeObject) w;
XtGeometryMask mode = request->request_mode;
XtGeometryResult answer;
Dimension old_height, old_width;
if ( !(mode & CWWidth) && !(mode & CWHeight) )
return(XtGeometryNo);
reply->width = request->width;
reply->height = request->height;
old_width = entry->rectangle.width;
old_height = entry->rectangle.height;
Layout(w, &(reply->width), &(reply->height) );
/*
* Since we are an override shell and have no parent there is no one to
* ask to see if this geom change is okay, so I am just going to assume
* we can do whatever we want. If you subclass be very careful with this
* assumption, it could bite you.
*
* Chris D. Peterson - Sept. 1989.
*/
if ( (reply->width == request->width) &&
(reply->height == request->height) ) {
if ( mode & XtCWQueryOnly ) { /* Actually perform the layout. */
entry->rectangle.width = old_width;
entry->rectangle.height = old_height;
}
else {
Layout(( Widget) cmw, (Dimension *)NULL, (Dimension *)NULL);
}
answer = XtGeometryDone;
}
else {
entry->rectangle.width = old_width;
entry->rectangle.height = old_height;
if ( ((reply->width == request->width) && !(mode & CWHeight)) ||
((reply->height == request->height) && !(mode & CWWidth)) ||
((reply->width == request->width) &&
(reply->height == request->height)) )
answer = XtGeometryNo;
else {
answer = XtGeometryAlmost;
reply->request_mode = 0;
if (reply->width != request->width)
reply->request_mode |= CWWidth;
if (reply->height != request->height)
reply->request_mode |= CWHeight;
}
}
return(answer);
}
/* Function Name: ChangeManaged
* Description: called whenever a new child is managed.
* Arguments: w - the complex menu widget.
* Returns: none.
*/
static void
ChangeManaged(Widget w)
{
Layout(w, (Dimension *)NULL, (Dimension *)NULL);
}
/************************************************************
*
* Global Action Routines.
*
* These actions routines will be added to the application's
* global action list.
*
************************************************************/
/* Function Name: PositionMenuAction
* Description: Positions the complex menu widget.
* Arguments: w - a widget (no the complex menu widget.)
* event - the event that caused this action.
* params, num_params - parameters passed to the routine.
* we expect the name of the menu here.
* Returns: none
*/
static void
PositionMenuAction(Widget w, XEvent *event, String *params,
Cardinal *num_params)
{
Widget menu;
XPoint loc;
if (*num_params != 1) {
char error_buf[BUFSIZ];
(void) sprintf(error_buf, "%s %s",
"Xaw - ComplexMenuWidget: position menu action expects only one",
"parameter which is the name of the menu.");
XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
return;
}
if ( (menu = FindMenu(w, params[0])) == NULL) {
char error_buf[BUFSIZ];
(void) sprintf(error_buf, "%s '%s'",
"Xaw - ComplexMenuWidget: could not find menu named: ", params[0]);
XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
return;
}
switch (event->type) {
case ButtonPress:
case ButtonRelease:
loc.x = event->xbutton.x_root;
loc.y = event->xbutton.y_root;
PositionMenu(menu, &loc);
break;
case EnterNotify:
case LeaveNotify:
loc.x = event->xcrossing.x_root;
loc.y = event->xcrossing.y_root;
PositionMenu(menu, &loc);
break;
case MotionNotify:
loc.x = event->xmotion.x_root;
loc.y = event->xmotion.y_root;
PositionMenu(menu, &loc);
break;
default:
PositionMenu(menu, (XPoint *)NULL);
break;
}
}
/************************************************************
*
* Widget Action Routines.
*
************************************************************/
/* Function Name: Unhighlight
* Description: Unhighlights current entry.
* Arguments: w - the complex menu widget.
* event - the event that caused this action.
* params, num_params - ** NOT USED **
* Returns: none
*/
static void
Unhighlight(Widget w, XEvent *event unused, String *params unused,
Cardinal *num_params unused)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
CmeObject entry = cmw->complex_menu.entry_set;
CmeObjectClass class;
if ( entry == NULL) return;
cmw->complex_menu.entry_set = NULL;
class = (CmeObjectClass) entry->object.widget_class;
(class->cme_class.unhighlight) ( (Widget) entry);
}
static void
SaveUnhighlight(Widget w, XEvent *event unused, String *params unused,
Cardinal *num_params unused)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
CmeObject entry = cmw->complex_menu.entry_set;
CmeObjectClass class;
if ( entry == NULL) return;
cmw->complex_menu.prev_entry = entry;
cmw->complex_menu.entry_set = NULL;
class = (CmeObjectClass) entry->object.widget_class;
(class->cme_class.unhighlight) ( (Widget) entry);
}
/* Function Name: LeftWindow
* Description: Mouse has left window, usually this means unhighlight
* Arguments: w - the complex menu widget.
* event - the event that caused this action.
* params, num_params - ** NOT USED **
* Returns: none
*/
static void
LeftWindow(Widget w, XEvent *event, String *params unused,
Cardinal *num_params unused)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
CmeObject entry = cmw->complex_menu.entry_set;
CmeObjectClass class;
String mn;
if ( entry == NULL) return;
mn = NULL;
XtVaGetValues((Widget) entry, XtNmenuName, &mn, NULL);
if (mn != NULL && GetRightEntry(w, event) == entry)
return;
cmw->complex_menu.prev_entry = NULL;
cmw->complex_menu.entry_set = NULL;
class = (CmeObjectClass) entry->object.widget_class;
(class->cme_class.unhighlight) ( (Widget) entry);
}
/* Function Name: Highlight
* Description: Highlights current entry.
* Arguments: w - the complex menu widget.
* event - the event that caused this action.
* params, num_params - ** NOT USED **
* Returns: none
*/
static void
Highlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
CmeObject entry;
CmeObjectClass class;
ShellWidget shell_widget = (ShellWidget)w;
#if defined(CmeDebug)
printf("Highlight(%x)\n", w);
#endif
if (shell_widget->shell.popped_up != TRUE) {
#if defined(CmeDebug)
printf("bogus\n");
#endif
return;
}
if ( !XtIsSensitive(w) ) return;
entry = GetEventEntry(w, event);
if (entry == cmw->complex_menu.entry_set) return;
Unhighlight(w, event, params, num_params);
if (entry == NULL) return;
if ( !XtIsSensitive( (Widget) entry)) {
cmw->complex_menu.entry_set = NULL;
return;
}
cmw->complex_menu.entry_set = entry;
class = (CmeObjectClass) entry->object.widget_class;
(class->cme_class.highlight) ( (Widget) entry);
}
/* Function Name: Notify
* Description: Notify user of current entry.
* Arguments: w - the complex menu widget.
* event - the event that caused this action.
* params, num_params - ** NOT USED **
* Returns: none
*/
static void
Notify(Widget w, XEvent *event unused, String *params unused,
Cardinal *num_params unused)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
CmeObject entry = cmw->complex_menu.entry_set;
CmeObjectClass class;
if (entry == NULL)
entry = cmw->complex_menu.prev_entry;
if ( (entry == NULL) || !XtIsSensitive((Widget) entry) ) return;
if (cmw->complex_menu.parent != NULL) {
#if defined(CmeDebug)
printf("Notify(%x): deferring to %x to parent %x\n", w, entry,
cmw->complex_menu.parent);
#endif
XtVaSetValues(cmw->complex_menu.parent, XtNcMdefer, (Widget)entry,
NULL);
return;
}
#if defined(CmeDebug)
else
printf("Notify(%x): not deferring\n", w);
#endif
if (cmw->complex_menu.deferred_notify != NULL) {
#if defined(CmeDebug)
printf("Notify: using deferred %x\n", w,
cmw->complex_menu.deferred_notify);
#endif
entry = (CmeObject)cmw->complex_menu.deferred_notify;
}
class = (CmeObjectClass) entry->object.widget_class;
(class->cme_class.notify)( (Widget) entry );
}
/************************************************************
*
* Public Functions.
*
************************************************************/
/* Function Name: XawComplexMenuAddGlobalActions
* Description: adds the global actions to the complex menu widget.
* Arguments: app_con - the appcontext.
* Returns: none.
*/
void
XawComplexMenuAddGlobalActions(XtAppContext app_con)
{
XtInitializeWidgetClass(complexMenuWidgetClass);
XmuCallInitializers( app_con );
}
/* Function Name: XawComplexMenuGetActiveEntry
* Description: Gets the currently active (set) entry.
* Arguments: w - the cmw widget.
* Returns: the currently set entry or NULL if none is set.
*/
Widget
XawComplexMenuGetActiveEntry(Widget w)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
return( (Widget) cmw->complex_menu.entry_set);
}
/* Function Name: XawComplexMenuClearActiveEntry
* Description: Unsets the currently active (set) entry.
* Arguments: w - the cmw widget.
* Returns: none.
*/
void
XawComplexMenuClearActiveEntry(Widget w)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
cmw->complex_menu.entry_set = NULL;
cmw->complex_menu.prev_entry = NULL;
}
/************************************************************
*
* Private Functions.
*
************************************************************/
/* Function Name: CreateLabel
* Description: Creates a the menu label.
* Arguments: w - the cmw widget.
* Returns: none.
*
* Creates the label object and makes sure it is the first child in
* in the list.
*/
static void
CreateLabel(Widget w)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
register Widget * child, * next_child;
register int i;
Arg args[2];
if ( (cmw->complex_menu.label_string == NULL) ||
(cmw->complex_menu.label != NULL) ) {
char error_buf[BUFSIZ];
(void) sprintf(error_buf, "Xaw Complex Menu Widget: %s or %s, %s",
"label string is NULL", "label already exists",
"no label is being created.");
XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
return;
}
XtSetArg(args[0], XtNlabel, cmw->complex_menu.label_string);
XtSetArg(args[1], XtNjustify, XtJustifyCenter);
cmw->complex_menu.label = (CmeObject)
XtCreateManagedWidget("menuLabel",
cmw->complex_menu.label_class, w,
args, TWO);
next_child = NULL;
for (child = cmw->composite.children + cmw->composite.num_children,
i = cmw->composite.num_children ; i > 0 ; i--, child--) {
if (next_child != NULL)
*next_child = *child;
next_child = child;
}
*child = (Widget) cmw->complex_menu.label;
}
/* Function Name: Layout
* Description: lays the menu entries out all nice and neat.
* Arguments: w - See below (+++)
* width_ret, height_ret - The returned width and
* height values.
* Returns: none.
*
* if width == NULL || height == NULL then it assumes the you do not care
* about the return values, and just want a relayout.
*
* if this is not the case then it will set width_ret and height_ret
* to be width and height that the child would get if it were layed out
* at this time.
*
* +++ "w" can be the complex menu widget or any of its object children.
*/
static void
Layout(Widget w, Dimension *width_ret, Dimension *height_ret)
{
CmeObject current_entry, *entry;
ComplexMenuWidget cmw;
Dimension width, height;
Boolean do_layout = ((height_ret == NULL) || (width_ret == NULL));
Boolean allow_change_size;
height = 0;
if ( XtIsSubclass(w, complexMenuWidgetClass) ) {
cmw = (ComplexMenuWidget) w;
current_entry = NULL;
}
else {
cmw = (ComplexMenuWidget) XtParent(w);
current_entry = (CmeObject) w;
}
allow_change_size = (!XtIsRealized((Widget)cmw) ||
(cmw->shell.allow_shell_resize));
if ( cmw->complex_menu.menu_height )
height = cmw->core.height;
else
if (do_layout) {
height = cmw->complex_menu.top_margin;
ForAllChildren(cmw, entry) {
if (!XtIsManaged( (Widget) *entry)) continue;
if ( (cmw->complex_menu.row_height != 0) &&
(*entry != cmw->complex_menu.label) )
(*entry)->rectangle.height = cmw->complex_menu.row_height;
(*entry)->rectangle.y = height;
(*entry)->rectangle.x = 0;
height += (*entry)->rectangle.height;
}
height += cmw->complex_menu.bottom_margin;
}
else {
if ((cmw->complex_menu.row_height != 0) &&
(current_entry != cmw->complex_menu.label) )
height = cmw->complex_menu.row_height;
}
if (cmw->complex_menu.menu_width)
width = cmw->core.width;
else if ( allow_change_size )
width = GetMenuWidth((Widget) cmw, (Widget) current_entry);
else
width = cmw->core.width;
if (do_layout) {
ForAllChildren(cmw, entry)
if (XtIsManaged( (Widget) *entry))
(*entry)->rectangle.width = width;
if (allow_change_size)
MakeSetValuesRequest((Widget) cmw, width, height);
}
else {
*width_ret = width;
if (height != 0)
*height_ret = height;
}
}
/* Function Name: AddPositionAction
* Description: Adds the XawPositionComplexMenu action to the global
* action list for this appcon.
* Arguments: app_con - the application context for this app.
* data - NOT USED.
* Returns: none.
*/
static void
AddPositionAction(XtAppContext app_con, caddr_t data unused)
{
static XtActionsRec pos_action[] = {
{ "XawPositionComplexMenu", PositionMenuAction },
};
XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
}
/* Function Name: FindMenu
* Description: Find the menu give a name and reference widget.
* Arguments: widget - reference widget.
* name - the menu widget's name.
* Returns: the menu widget or NULL.
*/
static Widget
FindMenu(Widget widget, String name)
{
register Widget w, menu;
for ( w = widget ; w != NULL ; w = XtParent(w) )
if ( (menu = XtNameToWidget(w, name)) != NULL )
return(menu);
return(NULL);
}
/* Function Name: PositionMenu
* Description: Places the menu
* Arguments: w - the complex menu widget.
* location - a pointer the the position or NULL.
* Returns: none.
*/
static void
PositionMenu(Widget w, XPoint *location)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
CmeObject entry;
XPoint t_point;
if (location == NULL) {
Window junk1, junk2;
int root_x, root_y, junkX, junkY;
unsigned int junkM;
location = &t_point;
if (XQueryPointer(XtDisplay(w), XtWindow(w), &junk1, &junk2,
&root_x, &root_y, &junkX, &junkY, &junkM) == FALSE) {
char error_buf[BUFSIZ];
(void) sprintf(error_buf, "%s %s", "Xaw - ComplexMenuWidget:",
"Could not find location of mouse pointer");
XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
return;
}
location->x = (short) root_x;
location->y = (short) root_y;
}
/*
* The width will not be correct unless it is realized.
*/
XtRealizeWidget(w);
location->x -= (Position) w->core.width/2;
if (cmw->complex_menu.popup_entry == NULL)
entry = cmw->complex_menu.label;
else
entry = cmw->complex_menu.popup_entry;
if (entry != NULL)
location->y -= entry->rectangle.y + entry->rectangle.height/2;
MoveMenu(w, (Position) location->x, (Position) location->y);
}
/* Function Name: MoveMenu
* Description: Actually moves the menu, may force it to
* to be fully visable if menu_on_screen is TRUE.
* Arguments: w - the complex menu widget.
* x, y - the current location of the widget.
* Returns: none
*/
static void
MoveMenu(Widget w, Position x, Position y)
{
Arg arglist[2];
Cardinal num_args = 0;
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
if (cmw->complex_menu.menu_on_screen) {
int width = w->core.width + 2 * w->core.border_width;
int height = w->core.height + 2 * w->core.border_width;
if (x >= 0) {
int scr_width = WidthOfScreen(XtScreen(w));
if (x + width > scr_width)
x = scr_width - width;
}
if (x < 0)
x = 0;
if (y >= 0) {
int scr_height = HeightOfScreen(XtScreen(w));
if (y + height > scr_height)
y = scr_height - height;
}
if (y < 0)
y = 0;
}
XtSetArg(arglist[num_args], XtNx, x); num_args++;
XtSetArg(arglist[num_args], XtNy, y); num_args++;
XtSetValues(w, arglist, num_args);
}
/* Function Name: ChangeCursorOnGrab
* Description: Changes the cursor on the active grab to the one
* specified in out resource list.
* Arguments: w - the widget.
* junk, garbage - ** NOT USED **.
* Returns: None.
*/
static void
ChangeCursorOnGrab(Widget w, XtPointer junk unused, XtPointer garbage unused)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
#if defined(CmeDebug)
printf("ChangeCursorOnGrab(%x): parent=%x\n", w, cmw->complex_menu.parent);
#endif
cmw->complex_menu.deferred_notify = NULL;
cmw->complex_menu.prev_entry = NULL;
/*
* The event mask here is what is currently in the MIT implementation.
* There really needs to be a way to get the value of the mask out
* of the toolkit (CDP 5/26/89).
*/
XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask|ButtonReleaseMask,
cmw->complex_menu.cursor,
XtLastTimestampProcessed(XtDisplay(w)));
}
static void
ClearParent(Widget w, XtPointer junk unused, XtPointer garbage unused)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
#if defined(CmeDebug)
printf("ClearParent(%x): parent=%x\n", w, cmw->complex_menu.parent);
#endif
Notify(w, (XEvent *)NULL, (String *)NULL, (Cardinal *)NULL);
cmw->complex_menu.parent = NULL;
}
/* Function Name: MakeSetValuesRequest
* Description: Makes a (possibly recursive) call to SetValues,
* I take great pains to not go into an infinite loop.
* Arguments: w - the complex menu widget.
* width, height - the size of the ask for.
* Returns: none
*/
static void
MakeSetValuesRequest(Widget w, Dimension width, Dimension height)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
Arg arglist[2];
Cardinal num_args = (Cardinal) 0;
if ( !cmw->complex_menu.recursive_set_values ) {
if ( (cmw->core.width != width) || (cmw->core.height != height) ) {
cmw->complex_menu.recursive_set_values = TRUE;
XtSetArg(arglist[num_args], XtNwidth, width); num_args++;
XtSetArg(arglist[num_args], XtNheight, height); num_args++;
XtSetValues(w, arglist, num_args);
}
else if (XtIsRealized( (Widget) cmw))
Redisplay((Widget) cmw, (XEvent *) NULL, (Region) NULL);
}
cmw->complex_menu.recursive_set_values = FALSE;
}
/* Function Name: GetMenuWidth
* Description: Sets the length of the widest entry in pixels.
* Arguments: w - the complex menu widget.
* Returns: width of menu.
*/
static Dimension
GetMenuWidth(Widget w, Widget w_ent)
{
CmeObject cur_entry = (CmeObject) w_ent;
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
Dimension width, widest = (Dimension) 0;
CmeObject * entry;
if ( cmw->complex_menu.menu_width )
return(cmw->core.width);
ForAllChildren(cmw, entry) {
XtWidgetGeometry preferred;
if (!XtIsManaged( (Widget) *entry)) continue;
if (*entry != cur_entry) {
XtQueryGeometry((Widget) *entry, NULL, &preferred);
if (preferred.request_mode & CWWidth)
width = preferred.width;
else
width = (*entry)->rectangle.width;
}
else
width = (*entry)->rectangle.width;
if ( width > widest )
widest = width;
}
return(widest);
}
/* Function Name: GetMenuHeight
* Description: Sets the length of the widest entry in pixels.
* Arguments: w - the complex menu widget.
* Returns: width of menu.
*/
static Dimension
GetMenuHeight(Widget w)
{
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
CmeObject * entry;
Dimension height;
if (cmw->complex_menu.menu_height)
return(cmw->core.height);
height = cmw->complex_menu.top_margin + cmw->complex_menu.bottom_margin;
if (cmw->complex_menu.row_height == 0) {
ForAllChildren(cmw, entry)
if (XtIsManaged ((Widget) *entry))
height += (*entry)->rectangle.height;
} else
height += cmw->complex_menu.row_height * cmw->composite.num_children;
return(height);
}
/* Function Name: GetEventEntry
* Description: Gets an entry given an event that has X and Y coords.
* Arguments: w - the complex menu widget.
* event - the event.
* Returns: the entry that this point is in.
*/
static CmeObject
GetEventEntry(Widget w, XEvent *event)
{
Position x_loc = 0, y_loc = 0;
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
CmeObject * entry;
switch (event->type) {
case MotionNotify:
x_loc = event->xmotion.x;
y_loc = event->xmotion.y;
break;
case EnterNotify:
case LeaveNotify:
x_loc = event->xcrossing.x;
y_loc = event->xcrossing.y;
break;
case ButtonPress:
case ButtonRelease:
x_loc = event->xbutton.x;
y_loc = event->xbutton.y;
break;
default:
XtAppError(XtWidgetToApplicationContext(w),
"Unknown event type in GetEventEntry().");
break;
}
if ( (x_loc < 0) || (x_loc >= (int)cmw->core.width) || (y_loc < 0) ||
(y_loc >= (int)cmw->core.height) )
return(NULL);
ForAllChildren(cmw, entry) {
if (!XtIsManaged ((Widget) *entry)) continue;
if ( ((*entry)->rectangle.y < y_loc) &&
((*entry)->rectangle.y + (int) (*entry)->rectangle.height > y_loc) ) {
if ( *entry == cmw->complex_menu.label )
return(NULL); /* cannot select the label. */
else
return(*entry);
}
}
return(NULL);
}
/* Function Name: GetRightEntry
* Description: Gets an entry given a crossing event that has X and Y
* coords, unless it exited to the right.
* Arguments: w - the complex menu widget.
* event - the event.
* Returns: the entry that this point is in.
*/
static CmeObject
GetRightEntry(Widget w, XEvent *event)
{
Position x_loc, y_loc;
ComplexMenuWidget cmw = (ComplexMenuWidget) w;
CmeObject * entry;
x_loc = event->xcrossing.x;
y_loc = event->xcrossing.y;
if ( (x_loc < 0) || /*(x_loc < (int)cmw->core.width) ||*/ (y_loc < 0) ||
(y_loc >= (int)cmw->core.height) )
return(NULL);
ForAllChildren(cmw, entry) {
if (!XtIsManaged ((Widget) *entry)) continue;
if ( ((*entry)->rectangle.y < y_loc) &&
((*entry)->rectangle.y + (int) (*entry)->rectangle.height > y_loc) ) {
if ( *entry == cmw->complex_menu.label )
return(NULL); /* cannot select the label. */
else
return(*entry);
}
}
return(NULL);
}
#endif /*]*/